package controllers;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Observer;

import model.SearchPhotoModel;
import model.SearchResultModel;
import model.PermissionModel;
import model.UserPermissions;
import model.WorldMapModel;
import view.SearchPhotoGUI;
import view.SearchResultGUI;
import view.WorldMapGUI;
import client.CliMessage;


/**
 * The Class SearchPhotoController.
 * controls the search action of a photo from the same location and hour requested.
 * @author Tomer Elkayam
 */
public class SearchPhotoController extends AbstractController
{
	
	/** The search view. */
	private SearchPhotoGUI searchView;
	
	/** The search model. */
	private SearchPhotoModel searchModel;
	
   /** The photos. */
   private ArrayList<SearchPhotoModel> photos;
   
   /** The user per. */
   private ArrayList<PermissionModel> userPer;
	
   public SearchPhotoController() 
   {
		super(null,null);
   }
   
   public SearchPhotoController(SearchPhotoModel searchModel) 
   {
		super(null,searchModel);
		this.searchModel = searchModel;
	
   }

   
	/**
	 * Instantiates a new search photo controller.
	 *
	 * @param searchView the search view
	 * @param searchModel the search model
	 */
	public SearchPhotoController(SearchPhotoGUI searchView,
			SearchPhotoModel searchModel) 
	{
		super(searchView,searchModel);
		this.searchModel = searchModel;
		this.searchView = searchView;
		searchView.setVisible(true);
		searchView.addSearchActionListener(new SearchButtonListener());
		searchView.addWorldMapActionListener(new WorldMapListener(this));
	}

	
	
	/**
	 * The listener for receiving "world map" button click events  events.
	 * The object created with this class is registered with a component using the
	 * component's <code>addWorldMapListener<code> method. When
	 * the worldMap event occurs, that object's appropriate
	 * method is invoked , and the world map s displayed.
	 *
	 * @see WorldMapEvent
	 */
	class WorldMapListener extends AbstractListener
	{
		
		/** The previous observer. */
		Observer previousObserver;
		
		/**
		 * Instantiates a new world map listener.
		 *
		 * @param previousObserver the previous observer
		 */
		WorldMapListener(Observer previousObserver)
		{
			 this.previousObserver = previousObserver;
		}

		/* (non-Javadoc)
		 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
		 */
		@Override
		public void actionPerformed(ActionEvent e) 
		{
			//create a new world map gui 
			WorldMapModel mapModel = new WorldMapModel();
			WorldMapGUI mapView = new WorldMapGUI(searchView);
			WorldMapController mapController = new WorldMapController(mapView, mapModel);
			
			//set the observer and back button listener
			setCurrentObserver(mapController);
			
			setBackListener(previousObserver,mapView);
			mapView.setVisible(true);
			
		}
		
	}
	
	
	
	/**
	 * The listener for receiving searchButton click events.
	 * The object created with this class is registered with a component using the
	 * component's <code>addSearchButtonListener<code> method. When
	 * the searchButton event occurs , the input is validated .
	 * <br> if correct ,all photos from the same location and a time stamp within the range of the same hour
	 * are being searched in the data base.	
	 *  
	 * @see SearchButtonEvent
	 */
	class SearchButtonListener implements ActionListener , IValidateInput
	{
		
		
		@Override
		public boolean validateInput() 
		{
			
			try
			{
				//if there is no location entered or the location is not an integer - an exception is thrown
				if(searchView.getLocationString() == null)
					throw new IOException();
				Integer.parseInt(searchView.getLocationString());
				return true;
			}
			catch(Exception e)
			{
				//catch an exception thrown and inform user
				searchView.displayInfoMessage("Error: location must consist of digits only!",
												"Invalid input", 0);
				e.printStackTrace();
				return false;
			}
		}
		
		
		@Override
		public void actionPerformed(ActionEvent e) 
		{
			//validate the input
			if(!validateInput())
				return;
			
			//save retrieved data
			int location = Integer.parseInt(searchView.getLocationString());
			String timeStamp = searchView.getTimestamp();
			searchModel.setLocation(location);
			searchModel.setTimeStamp(timeStamp);
			
			//get current user id
			UserPermissions up = UserPermissions.getInstance(0, null, null);
			int uid = up.getCurrUserID();
			
			//record the search in DB
			String insertQuary = "adu" + "INSERT INTO cus_search_history " 
                    + "(uid,requestedlocation,requestedtimeStamp) VALUES "
	                 + "("+ uid +","+ location +",'"+ timeStamp +"')";;
			
			sendToServer(insertQuary);
		
		}
		
	}


	@Override
	public void handleDBRequestSuccess() 
	{
		//get time stamp and location form model
		String timeStamp = searchModel.getTimeStamp();
		int location = searchModel.getLocation();
		
		//send a photo search query of photos from same hour
		String sameDateAndHouer = timeStamp.substring(0,11) + timeStamp.substring(11,13);
		String startDate = sameDateAndHouer+":00:00";
		String endDate =  sameDateAndHouer+":59:59";
		
		System.out.println("user has requested to search: location:"+location+" time stamp:"+timeStamp);
		String searchQuary = "search" +	"SELECT p.timestamp , p.location , p.linktofile "
										+"FROM photos AS p "
										+"WHERE p.Location = "+location+" "
										+"AND p.TimeStamp BETWEEN '"+startDate+"' AND '"+endDate+"'";
		
		sendToServer(searchQuary);
		
	}

	
	@Override
	public void handleNullSearchResult() 
	{
		System.out.println("inform user: no such photo!");
		searchView.displayInfoMessage("There are no photos matching serach information."
										,"Photos Not Found", 1);
	}

	
	@Override
	public void handleDBSearchResult(CliMessage dbResult) 
	{
		//get the time stamp , location and the link to file and save it to the model
		ArrayList<SearchPhotoModel> photoHeadlineList = new ArrayList<SearchPhotoModel>();
		srs = dbResult.getSrs();
		int nRows = srs.size();
		String dataTable[][] = createDataTable(srs);
		
		//get all tuples
		for(int i = 0 ; i < nRows ; i++)
		{
			// get a tuple
			HashMap<String, String> photoTuple = srs.get(i);
			
			//get the time stamp , location and the link to file
			int location = Integer.parseInt(photoTuple.get("LOCATION"));
			String timeStamp = photoTuple.get("TIMESTAMP");
			String linkToFile = photoTuple.get("LINKTOFILE");
			
			//set a photo detail class
			SearchPhotoModel photoDetails = new SearchPhotoModel(timeStamp,location,linkToFile) ;
			
			//add the photo details to the list
			photoHeadlineList.add(photoDetails);
			
			//display for developer
			System.out.println( location+" "+timeStamp+" "+linkToFile);
			
		}
		
		//create the model and view
		SearchResultModel searchResModel  = new SearchResultModel(photoHeadlineList);
		SearchResultGUI searchResView = new SearchResultGUI("Search Result Window");
		searchResView.setTable(getColumnNames(srs), dataTable);
		
		//check if the user is an archive worker or a registered customer
		UserPermissions up = UserPermissions.getInstance(0, null,null);
		
		//set buttons according to user permissions
		String[] buttonNames;
		if(!up.userHasGroup("Archive Worker"))
		{
			buttonNames = new String[2];
			buttonNames[0] = "Buy Photo";
			buttonNames[1] = "Buy Sample";
		}
		else 
		{
			buttonNames = new String[1];
			buttonNames[0] ="View Photo";		
		}
		
		//create all the buttons and save them to the model
		searchResView.setAllbuttons(nRows, buttonNames);
		searchResModel.setButtonNames(buttonNames);
		
		//create a new controller
		SearchResultController searchResController = new SearchResultController(searchResView, searchResModel);
		
		//set the observer and back button listener
		setCurrentObserver(searchResController);
		
		setBackListener(this,searchResView);
		
		//display result window
		searchResView.setVisible(true);
		searchResView.displayInfoMessage("There are: "+nRows+" Photos found","Photos are found", 1);
	}
	
    /**
     * Sets the photos.
     *
     * @param pics the pics
     */
    public void SetPhotos(ArrayList<SearchPhotoModel> pics)
    {
    	photos=new ArrayList<SearchPhotoModel>();
    	
    	for(int i=0;i<pics.size();i++)
    	{
    		photos.add(new SearchPhotoModel(pics.get(i).getTimeStamp(),pics.get(i).getLocation(),pics.get(i).getLinkToFile()));
    	}
    }
    
    /**
     * Check photo exist.
     *
     * @return true, if successful
     */
    public boolean checkPhotoExist()
    {
    	
    	for(int i=0;i<photos.size();i++)
    	{
    		if((searchModel.getLocation()==photos.get(i).getLocation()) && searchModel.getTimeStamp().equals(photos.get(i).getTimeStamp()))
    		{
    			System.out.println("Photo Exist...");
    			return true;
    		}
    	}
    	
    	
    	System.out.println("Photo does not Exist");
    	return false;
    }
    
    /**
 	 * Sets the user permissions.
 	 *
 	 * @param user the new user permissions
 	 */
 	public void setUserPermissions(ArrayList<PermissionModel> user)
	  {
		 userPer=new ArrayList<PermissionModel>();
		
	    	for(int i=0;i<user.size();i++)
	    	{
	    		userPer.add(new PermissionModel(user.get(i).getUID(),user.get(i).getGroupID(),user.get(i).getGroupName()));
	    	}
	   }
    
    /**
     * Check permission.
     *
     * @param user the user
     * @return true, if successful
     */
    public boolean checkPermission(ArrayList<PermissionModel> user)
    {
    	//archive or registered
    	
    	for(int i=0;i<userPer.size();i++)
		{
		  for(int j=0;j<user.size();j++)	
		  {
		   if(user.get(j).getGroupName().equals("Archive Worker") && userPer.get(i).getUID()==user.get(j).getUID())
		    {
			   System.out.println("Archive Worker");
   			  return true;
		    }
		  }
		}
		
    	System.out.println("Registerd Customer");
    	return false;
   	
    }
	
	/**
	 * Creates the data table.
	 *
	 * @param srs the serialized result set
	 * @return the string[][]
	 */
	private String[][] createDataTable(ArrayList<HashMap<String, String>> srs)
	{
		int nRows = srs.size();
		int nCols = srs.get(0).keySet().size();
		
		//create data table
		 String[][] dataTable = new String[nRows][nCols];
		//get all keys
		 String[] columnNames = getColumnNames(srs);
		 	
		 //set data table
		 for (int j = 0; j < nRows; j++) 
		 {
			 for (int k = 0; k < nCols; k++) 
			 {
				 dataTable[j][k] = srs.get(j).get(columnNames[k]);
			 }
		 }
		 
		 return dataTable;
	}
	
	/**
	 * Gets the column names.
	 *
	 * @param srs the serialized result set
	 * @return the column names
	 */
	private String[] getColumnNames(ArrayList<HashMap<String, String>> srs)
	{
		int nCols = srs.get(0).keySet().size();
		 String[] columnNames = new String[nCols];
		 int i = 0;
		 for (String key : srs.get(0).keySet()) 
			 columnNames[i++] = key;
		 return columnNames;
	}
	
}
